package com.voc.im.xmpp;

import com.voc.im.utils.RandomUntil;
import com.voc.im.xmpp.listener.IMConnectionListener;
import org.jetbrains.annotations.NotNull;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.StanzaTypeFilter;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smackx.bookmarks.BookmarkManager;
import org.jivesoftware.smackx.iqregister.AccountManager;
import org.jivesoftware.smackx.muc.*;
import org.jivesoftware.smackx.ping.PingManager;
import org.jivesoftware.smackx.vcardtemp.VCardManager;
import org.jivesoftware.smackx.vcardtemp.packet.VCard;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.Localpart;
import org.jxmpp.stringprep.XmppStringprepException;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;

public class IMConnection implements ConnectionListener, StanzaListener {

    private static volatile IMConnection imConnection = null;

    private AbstractXMPPConnection connection = null;

    private Roster mRosterManager = null;

    private ChatManager mChatManager = null;

    private MultiUserChatManager mMucManager = null;

    private BookmarkManager mBookmarkManager = null;

    private PingManager mPingManager = null;

    private Timer mTimerServer = null;

    private Map<String, MultiUserChat> mMultiUserChatMap = new HashMap<String, MultiUserChat>();

    public static IMConnection getInstance() {
        if (imConnection == null) synchronized (IMConnection.class) {
            if (imConnection == null)
                imConnection = new IMConnection();
        }
        return imConnection;
    }

    private IMConnection() {
        initConnection();
    }

    /**
     * 初始化AbstractXMPPConnection
     */
    private void initConnection() {
        XMPPTCPConnectionConfiguration config = null;
        try {
            config = XMPPTCPConnectionConfiguration.builder()
                    //设置主机IP
                    .setHostAddress(InetAddress.getByName("101.37.253.11"))
                    //设置服务器名称
                    .setXmppDomain("openfire-voc")
                    //设置端口号
                    .setPort(5222)
                    //设置资源名
                    .setResource("SMACK_PC")
                    //设置离线状态
                    .setSendPresence(false)
                    //设置开启压缩
                    .setCompressionEnabled(true)
                    //禁用SSL连接
                    .setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)
                    .build();
        } catch (XmppStringprepException | UnknownHostException e) {
            e.printStackTrace();
        }
        if (config == null)
            return;
        //初始化连接
        connection = new XMPPTCPConnection(config);
        //连接监听
        connection.addConnectionListener(new IMConnectionListener());
        //过滤iq
        StanzaTypeFilter typeFilter = new StanzaTypeFilter(Presence.class);
        AndFilter andFilter = new AndFilter(typeFilter);
        //用户状态监听
        connection.addSyncStanzaListener((this), andFilter);
    }

    /**********************************连接监听****************************************/

    @Override
    public void connected(XMPPConnection connection) {

    }

    @Override
    public void authenticated(XMPPConnection connection, boolean resumed) {

    }

    @Override
    public void connectionClosed() {

    }

    @Override
    public void connectionClosedOnError(Exception e) {

    }

    @Override
    public void processStanza(Stanza packet) throws SmackException.NotConnectedException, InterruptedException, SmackException.NotLoggedInException {

    }

    /**
     * 判断连接是否通过了身份验证
     * 即登录成功
     *
     * @return true/false
     */
    public boolean isAuthenticated() {
        return connection != null && connection.isConnected()
                && connection.isAuthenticated();
    }

    /**
     * 判断连接是否成功
     *
     * @return true/false
     */
    private boolean isConnected() {
        return connection != null && connection.isConnected();
    }

    /**
     * 断开连接
     */
    public void disconnect() {
        if (isConnected()) {
            connection.disconnect();
        }
    }

    /**
     * 连接登录
     *
     * @param username 账户
     * @param password 密码
     * @return 成功true 失败false
     */
    public boolean connectLogin(String username, String password) throws Exception {
        this.disconnect();
        if (connection == null) {
            throw new Exception("AbstractXMPPConnection未初始化");
        }
        connection.connect().login(username, password);
        return connection.isAuthenticated();
    }

    /**
     * 获取账户信息
     *
     * @return Map<String, String> 账户信息
     */
    public Map<String, String> getAccountAttribute() throws Exception {
        if (!isAuthenticated()) {
            throw new Exception("客户端未连接-认证");
        }
        AccountManager accountManager = AccountManager.getInstance(connection);
        Map<String, String> accountMaps = new HashMap<>();
        for (String key : accountManager.getAccountAttributes()) {
            accountMaps.put(key, accountManager.getAccountAttribute(key));
        }
        accountMaps.put("jid", connection.getUser().asEntityBareJidString());
        return accountMaps;
    }

    /**
     * 用户注册
     */
    public String accountCreate(String nickname, String password) throws Exception {
        if (connection == null) {
            throw new Exception("AbstractXMPPConnection未初始化");
        }
        connection.connect();
        if (!connection.isConnected()) {
            throw new Exception("客户端连接失败");
        }
        //注册
        AccountManager manager = AccountManager.getInstance(connection);
        manager.sensitiveOperationOverInsecureConnection(true);
        String username = RandomUntil.getNumLetter(9);
        while (Integer.parseInt(username.substring(0, 1)) == 0) {
            username = RandomUntil.getNumLetter(9);
        }
        Map<String, String> maps = new HashMap<>();
        maps.put("name", nickname);
        manager.createAccount(Localpart.from(username), password, maps);
        return username;
    }

    /**
     * 查看用户是否设置了vcard
     */
    public boolean isUserVCard() throws Exception {
        VCard vCard = VCardManager.getInstanceFor(connection).loadVCard();
        return vCard.getNickName() != null && vCard.getField("sex") != null && vCard.getField("address") != null;
    }

    /**
     * 获取用户VCard信息
     */
    public VCard getUserVCard() throws Exception {
        if (!isAuthenticated()) {
            throw new Exception("客户端未连接-认证");
        }
        return VCardManager.getInstanceFor(connection).loadVCard();
    }

    /**
     * 获取用户VCard信息
     *
     * @param userJid 用户JID
     */
    public VCard getUserVCard(String userJid) throws Exception {
        if (!isAuthenticated()) {
            throw new Exception("客户端未连接-认证");
        }
        EntityBareJid bareJid = JidCreate.entityBareFrom(userJid);
        return VCardManager.getInstanceFor(connection).loadVCard(bareJid);
    }

    /**
     * 设置账号VCard信息
     */
    public void setUserVCard(@NotNull String nickname, @NotNull String userSex, @NotNull String address, String autograph, @NotNull File file) throws Exception {
        if (!isAuthenticated()) {
            throw new Exception("客户端未连接-认证");
        }
        VCardManager manager = VCardManager.getInstanceFor(connection);
        VCard vCard = manager.loadVCard();
        vCard.setNickName(nickname);
        vCard.setField("sex", userSex);
        vCard.setField("region", address);
        vCard.setField("autograph", autograph);
        vCard.setAvatar(bytesImageFile(file));
        manager.saveVCard(vCard);
    }

    /**
     * 修改用户名
     *
     * @param nickname 用户名
     */
    public void changeUserVCardToNickname(@NotNull String nickname) throws Exception {
        if (!isAuthenticated()) {
            throw new Exception("客户端未连接-认证");
        }
        VCardManager manager = VCardManager.getInstanceFor(connection);
        VCard vCard = manager.loadVCard();
        vCard.setNickName(nickname);
        manager.saveVCard(vCard);
    }

    /**
     * 修改用户性别
     *
     * @param userSex 用户性别
     */
    public void changeUserVCardToUserSex(@NotNull String userSex) throws Exception {
        if (!isAuthenticated()) {
            throw new Exception("客户端未连接-认证");
        }
        VCardManager manager = VCardManager.getInstanceFor(connection);
        VCard vCard = manager.loadVCard();
        vCard.setField("sex", userSex);
        manager.saveVCard(vCard);
    }

    /**
     * 修改用户签名
     *
     * @param autograph 用户签名
     */
    public void changeUserVCardToAutograph(@NotNull String autograph) throws Exception {
        if (!isAuthenticated()) {
            throw new Exception("客户端未连接-认证");
        }
        VCardManager manager = VCardManager.getInstanceFor(connection);
        VCard vCard = manager.loadVCard();
        vCard.setField("autograph", autograph);
        manager.saveVCard(vCard);
    }

    /**
     * 修改用户地址
     *
     * @param address 用户家庭地址
     */
    public void changeUserVCardToAddress(@NotNull String address) throws Exception {
        if (!isAuthenticated()) {
            throw new Exception("客户端未连接-认证");
        }
        VCardManager manager = VCardManager.getInstanceFor(connection);
        VCard vCard = manager.loadVCard();
        vCard.setField("region", address);
        manager.saveVCard(vCard);
    }

    /**
     * 修改用户头像
     *
     * @param file 图片
     */
    public void changeUserVCardToHeardImg(@NotNull File file) throws Exception {
        if (!isAuthenticated()) {
            throw new Exception("客户端未连接-认证");
        }
        VCardManager manager = VCardManager.getInstanceFor(connection);
        VCard vCard = manager.loadVCard();
        vCard.setAvatar(bytesImageFile(file));
        manager.saveVCard(vCard);
    }

    /**
     * 获取文件byte[]
     */
    private byte[] bytesImageFile(@NotNull File file) throws Exception {

        String fileName = file.getName();
        String suffix = fileName.substring(fileName.indexOf("."));
        if (!suffix.contains("png") || !suffix.contains("PNG") ||
                !suffix.contains("jpg") || !suffix.contains("JPG")) {
            throw new Exception("文件类型错误-" + fileName);
        }

        FileInputStream fis = new FileInputStream(file);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        byte[] bytes = new byte[1024];
        int n;
        while ((n = fis.read(bytes)) != -1) {
            bos.write(bytes, 0, n);
        }
        fis.close();
        bos.close();

        return bos.toByteArray();
    }
}
